// QuadraticFunction.cpp
// QuadraticFunction member-function definitions. This file contains
// implementations of the member functions prototyped in QuadraticFunction.h
#include <iostream> // allows program to perform input and output
#include <iomanip> // parameterized stream manipulators
#include <string> // program uses C++ standard string class
#include <cmath> // program uses C++ standard math library
#include "QuadraticFunction.h" // include definition of class QuadraticFunction
#include <complex>
using namespace std; // program uses names from the std namespace

// constructor initializes the constants with doubles supplied as arguments
QuadraticFunction::QuadraticFunction( double a, double b, double c)
{
	setConstants( a, b, c); // validate and store constants
} // end Quadratic constructor

// function to set the constants for the terms of the quadratic equation;
// ensures that there is a quadratic term.
void QuadraticFunction::setConstants( double a, double b, double c )
{       
    
	A = a;
	B = b;
	C = c;
        if (A==0 & B==0)
        {equationType="Constant";}
        else if (A==0)
        {equationType= "Linear";}
        else{ equationType= "Quadratic";}
        
} // end function setConstants

// function to compute the Discriminant
double QuadraticFunction::computeDiscriminant()
{
	return B*B - 4*A*C;
} // end function computeDiscriminant

// function to use the simplified Quadratic Formula to compute the only solution
void QuadraticFunction::computeOnlyOneSolution()
{
	// use the simplified Quadratic Formula to compute and display the only solution
	cout << "The Quadratic Equation has only one solution:" << endl;
	cout << "x = " << -B / ( 2 * A ) << endl << endl;
} // end function computeOnlyOneSolution

// function to use the Quadratic Formula to compute the 2 real solutions 
void QuadraticFunction::computeQuadraticFormula()
{
	double X1, X2; // variables to hold the 2 real solutions

	// use the Quadratic Formula to compute the 2 real solutions
	X1 = ( -B + sqrt( B*B - 4*A*C ) ) / ( 2 * A );
	X2 = ( -B - sqrt( B*B - 4*A*C ) ) / ( 2 * A );

	// display the 2 real solutions
	cout << "The Quadratic Equation ( " << A << "x*x + ";
	cout << B << "x + " << C << " = 0 ) has two solutions:" << endl;
	cout << "x1 = " << X1 << endl << "x2 = " << X2 << endl << endl;
        
} // end function computeQuadraticFormula

// function to use the Quadratic Formula to compute the 2 real solutions 
void QuadraticFunction::computeComplexSolution()
{
	complex<double> X1, X2; // variables to hold the 2 real solutions
        complex<double>A1=A;
        complex<double>B1=B;
        complex<double>C1=C;
	// use the Quadratic Formula to compute the 2 real solutions
	X1 = ( -B1 + sqrt( B1*B1 - 4.0*A1*C1 ) ) / ( 2.0 * A1 );
	X2 = ( -B1 - sqrt( B1*B1 - 4.0*A1*C1 ) ) / ( 2.0 * A1);

	// display the 2 real solutions
	cout << "The Quadratic Equation ( " << A1 << "x*x + ";
	cout << B1 << "x + " << C1 << " = 0 ) has two complex solutions:" << endl;
	cout << "x1 = " << X1.real() << "+ "<< X1.imag() <<"i"<<endl << endl;
        cout << "x2 = " << X2.real() << "+ "<< X2.imag()<<"i" << endl << endl;
        
} // end function computeQuadraticFormula

//function to compute Y-intercept
void QuadraticFunction::computeYIntercept()
{
    //function used for linear equations (y=mx+b)
    //set x=0 then y=b which is the C term
    cout<<"The y-intercept is "<< C <<endl;
    
}
// function to determine the solution type of the Quadratic Equation
void QuadraticFunction::determineSolution()
{       
    if (equationType=="Quadratic"){
        
	// variable declaration
	double D = computeDiscriminant(); // call computeDiscriminant() and assign to D

	if ( D == 0.0 ) // if Discriminant is 0, there is only 1 solution
	{
		computeOnlyOneSolution(); // call computeOnlyOneSolution
	}
	else
	{
		if ( D > 0.0 ) // if Discriminant is positive, there are 2 real solutions
			computeQuadraticFormula();	// call computeQuadraticFormula

		if ( D < 0.0 ) // if Discriminant is negative, the roots are complex
                    computeComplexSolution();
	}
    }
    else if(equationType=="Linear")
    {computeYIntercept();}
         

} // end function determineSolution

// function to create and display an XY table according to the user's specs
void QuadraticFunction::createTableXY( )
{
	// variable declarations
	string tableTitle; // title for the table
	double X1; // stores the first x value
	double X2; // stores the last x value
	double X; // stores x values
	double Y; // stores y values
	int numPoints = 1; // table lists at least one point

	// prompt user to enter a title for the table
	cout << "Enter a Title for the table: ";
	cin.ignore( 1, 'n' );
	getline( cin, tableTitle ); // read string into tableTitle

	// prompt user for the first x-coordinate to start the list
	cout << "Enter the first x-coordinate to start the list: ";
	cin >> X1;
	// prompt user for the last x-coordinate to end the list
	cout << "Enter the last x-coordinate to end the list: ";
	cin >> X2;
	X = X1;

	if ( X1 != X2 )
	{
		// prompt user for the number of points to list
		do
		{
			cout << "Enter a size for the list: ";
			cin >> numPoints;
		} while (numPoints < 2);
	}

	// create the Table
	cout << endl << tableTitle << endl << endl; // start by displaying the title of the table
	cout << setw(20) << "X" << setw(20) << "Y\n" << endl; // label the x and y columns

	cout << fixed << setprecision(4); // set floating-point number format

	if ( X1 == X2 ) // if X1 and X2 are the same point, list that point
	{
		Y = A*X*X + B*X + C; // determine the corresponding y value
		cout << setw(20) << X << setw(20) << Y << endl; // display the x and y values
	}
	else
	{
		// calculate and display y values for each x value up to numPoints
		for ( int i = 0; i < numPoints; i++ )
		{
			Y = A*X*X + B*X + C; // determine the corresponding y value
			cout << setw(20) << X << setw(20) << Y << endl; // display x and y values
			X = X + (X2 - X1)/(numPoints - 1); // next x value
		}
	}
	cout << resetiosflags(ios::fixed); // unformat or restore default
} // end function createTableXY